"use strict";
/**
 * TPS的学习点
 */
class StudyPoint {
    constructor() {
        this.name = "";
        this.e = 0;
        this.n = 0;
        this.hi = 0;
        this.h = 0;
        /** 是否是定向点 */
        this.isOrient = false;
        /** 是否被选择 */
        this.selected = true;
    }
}
exports.StudyPoint = StudyPoint;
/**
 * TPS的测量点
 * 带1后缀的为盘左值
 * 带2后缀的为盘右值
 */
class SurveyPoint {
    constructor(e, n, h) {
        /** 是否被选择 */
        this.selected = true;
        /** 是否是定向点 */
        this.isOrient = false;
        this.name = "";
        this.e = 0;
        this.n = 0;
        this.hi = 0;
        this.h = 0;
        this.hz = 0;
        this.hv = 0;
        this.slope = 0;
        this.hz1 = 0;
        this.hv1 = 0;
        this.slope1 = 0;
        this.hz2 = 0;
        this.hv2 = 0;
        this.slope2 = 0;
        /** 归零后的水平角 */
        this.hz0 = 0; //归零后的Hz值
        this.dert = 0; //指标差
        /** 是否通过精度检验 */
        this.pass = false;
        this.time1 = new Date(); //盘左的测量时间
        this.time2 = new Date(); //盘右的测量时间
        this.e = e || 0;
        this.n = n || 0;
        this.h = h || 0;
    }
    /**
     * 计算测量点盘左盘右合并后的水平和垂直角,做2c和指标差矫正
     */
    calibrate(method) {
        (!method) && (method = ObserveMethod.FullCircle);
        if (method === ObserveMethod.FullCircle) {
            //这是盘左盘右都测量成功的情况
            if (this.slope1 !== 0 && this.slope2 !== 0) {
                this.hv = (this.hv1 + 2 * Math.PI - this.hv2) / 2;
                this.slope = (this.slope1 + this.slope2) / 2;
                var twoC = (this.hz1 + Math.PI - this.hz2) % (2 * Math.PI);
                if (twoC > Math.PI)
                    twoC = twoC - Math.PI * 2; //如果差值大于Pi,则转换成负角度
                this.hz = (this.hz1 - twoC / 2) % (Math.PI * 2);
                this.pass = true;
            }
            else if (this.slope1 === 0 && this.slope2 !== 0) {
                //这是只有盘右成功的
                this.hv = 2 * Math.PI - this.hv2;
                this.hz = (this.hz2 + Math.PI) % (2 * Math.PI);
                this.slope = this.slope2;
                this.pass = false; //只观测到半测回,无法通过精度检验
            }
            else {
                //这是只有盘左成功的或者全失败
                this.hz = this.hz1;
                this.hv = this.hv1;
                this.slope = this.slope1;
                this.pass = false; //只观测到半测回,无法通过精度检验
            }
        }
        else {
            this.hz = this.hz1;
            this.hv = this.hv1;
            this.slope = this.slope1;
            this.pass = (this.slope !== 0); //不需要精度检验,直接通过
        }
    }
}
exports.SurveyPoint = SurveyPoint;
class SurveyVector {
    constructor(pointA, pointB) {
        this.de = pointB.e - pointA.e;
        this.dn = pointB.n - pointA.n;
        this.dh = pointB.h - pointA.h;
    }
    /**
     * 获取全站仪坐标系下的水平角,即从N开始为0度,顺时针角度增加
     * @return {number} 以弧度为单位的水平角
     */
    get horizontalAngle() {
        return Math.PI / 2 * (2 - Math.sign(this.de + 1.0E-30)) - Math.atan(this.dn / (this.de + 1.0E-30));
    }
    /**
     * 获取垂直角,垂直角是以水平线为0度计算
     * @return {number} 以弧度为单位的垂直角
     */
    get verticalAngle() {
        return Math.atan(this.dh / (this.distance + 1.0E-30));
    }
    /**
     * 获取水平距离
     * @return {number} 获取水平距离
     */
    get distance() {
        return parseFloat(Math.sqrt(this.de * this.de + this.dn * this.dn).toFixed(6));
    }
    /**
     * 获取斜距
     * @return {number} 获取三维的斜距
     */
    get slope() {
        var slope = Math.sqrt(this.de * this.de + this.dn * this.dn + this.dh * this.dh);
        return parseFloat(slope.toFixed(6));
    }
}
exports.SurveyVector = SurveyVector;
/**
 * 全站仪的数据管理类
 */
class TPS {
    constructor(e, n, h) {
        /** 当前全站仪所处的正倒镜状态 */
        this._curFace = Face.Face1;
        /** 当前全站仪下的学习点集合 */
        this.studyPointList = [];
        /** 全站仪的测站坐标 */
        this.center = new SurveyPoint();
        this.center.e = e || 0;
        this.center.n = n || 0;
        this.center.h = h || 0;
    }
    /**
     * 设置盘左盘右,0为盘左,1为盘右
     */
    setFace(face) {
        if (typeof face === 'number') {
            this._curFace = (face === 0) ? Face.Face1 : Face.Face2;
        }
        else {
            this._curFace = face;
        }
    }
    /**
     * 获取盘左盘右,0为盘左,1为盘右
     */
    getFace() {
        return parseInt(this._curFace.toString());
    }
    /**
     * 获取该点所在的水平角
     */
    getHz(point) {
        if (!point)
            return 0;
        var v = new SurveyVector(this.center, point);
        var angle = v.horizontalAngle;
        if (this._curFace === Face.Face2) {
            angle += Math.PI;
            (angle > Math.PI * 2) && (angle = angle - 2 * Math.PI);
        }
        return angle;
    }
    /**
    * 获取该点到全站仪的斜距
    */
    getSlope(point) {
        if (!point)
            return 0;
        var v = new SurveyVector(this.center, point);
        return v.slope;
    }
    /**
    * 获取该点到全站仪的平距
    */
    getDist(point) {
        if (!point)
            return 0;
        var v = new SurveyVector(this.center, point);
        return v.distance;
    }
    /**
     * 获取点所在的垂直角,该垂直角是相对于全站仪的坐标系而言,即天顶方向为0度.
     */
    getHv(point) {
        if (!point)
            return 0;
        var v = new SurveyVector(this.center, point);
        var angle = Math.PI / 2 - v.verticalAngle;
        (this._curFace === Face.Face2) && (angle = Math.PI * 2 - angle);
        return angle;
    }
    /**
     * 将带有ENH坐标的测量点转换成全站仪坐标下的Hz,Hv
     */
    convertToAzimuth(key) {
        var pt = this.getPoint(key);
        var result = new SurveyPoint();
        if (!pt)
            return result;
        result.hz = this.getHz(pt);
        result.hv = this.getHv(pt);
        return result;
    }
    /**
     * 获取测点
     * @param {number|string} key 测点名称或序号
     */
    getPoint(key) {
        if (typeof (key) === 'string') {
            var pt = this.studyPointList.find((p) => {
                return p.name === key;
            });
            return pt;
        }
        else {
            return this.studyPointList[key];
        }
    }
    /**
     * 为全站仪增加测点
     */
    addPoint(ptName, point) {
        point.name = ptName;
        this.studyPointList.push(point);
    }
    /**
     * 将全站仪测量的水平,垂直,斜距转换成XYZ,返回测量点
     * @return {object} 测量点
     * @prop {number} E
     * @prop {number} N
     * @prop {number} H
     */
    convertToXYZ(hz, hv, slope) {
        if (this._curFace == Face.Face1) {
            hv = Math.PI / 2 - hv;
        }
        else {
            hv = Math.PI / 2 - (2 * Math.PI - hv);
            hz = hz - Math.PI;
        }
        var dist = slope * Math.cos(hv);
        var K = 0.13;
        var deltaH = 0;
        if (dist > 1000)
            deltaH = dist * dist * (1 - K) / 2 / 6378000;
        var point = new SurveyPoint(this.center.e + dist * Math.sin(hz), this.center.n + dist * Math.cos(hz), this.center.h + slope * Math.sin(hv) + deltaH);
        return point;
    }
    /**
     * 通过该点的方位和距离,计算该点的坐标
     */
    caculateCoor(pt) {
        var coor = this.convertToXYZ(pt.hz, pt.hv, pt.slope);
        pt.e = coor.e;
        pt.n = coor.n;
        pt.h = coor.h;
    }
    /**
     * 检查测量点是否测量正确(防止ATR瞄准到其他点上去)
     * 判断标准是同学习点的坐标相比,二者空间距离大于20cm则认为测量到其他点上去
     */
    checkSurveyPointValidate(ptName, hz, hv, slope) {
        var targetPoint = this.getPoint(ptName);
        var surveyPoint = this.convertToXYZ(hz, hv, slope);
        var v = new SurveyVector(targetPoint, surveyPoint);
        //2个点的空间距离小于.2m则认为是合格,没测到其他点上去
        if (v.distance < 0.2) {
            return true;
        } else {
            console.log(ptName, '较差过大,距离较差:', v.distance);
            return false;
        }
    }
    /**
     * 根据测量结果,给点赋值
     */
    parseResult(point, result) {
        var props = ['hz', 'hv', 'slope'];
        var suffix = this._curFace === Face.Face1 ? '1' : '2';
        for (let key of props) {
            point[key + suffix] = result[key];
        }
        //赋值时间
        point['time' + suffix] = new Date();
    }
}
exports.TPS = TPS;
/**
 * 一个测回所测的测量结果
 */
class SurveyTurn {
    constructor() {
        /**
         * 储存测量结果
         */
        this.surveyResultList = [];
    }
    /**
     * 矫正本测回的测量结果,加入归零差
     * @param {number} [zeroHz=0] - 初始的定向角,默认为0
     */
    calibrate(observeMethod, zeroHz) {
        !observeMethod && (observeMethod = ObserveMethod.FullCircle);
        zeroHz = zeroHz || 0;
        this.surveyResultList.forEach(function (pt) {
            //将盘左盘右数据赋值到最终的hz,hv,slope数据上
            pt.calibrate(observeMethod);
        });
        if (this._isZeroHzNeeded()) {
            var angle = 0;
            var firstPt = this.surveyResultList[0];
            var lastPt = this.surveyResultList[this.surveyResultList.length - 1];
            angle = (Math.abs(firstPt.hz - lastPt.hz) > 3.14) ?
                (firstPt.hz + lastPt.hz - 2 * Math.PI) :
                (firstPt.hz + lastPt.hz);
            angle = angle / 2;
            var zeroDiff = angle - zeroHz;
            this.surveyResultList.forEach(p => {
                p.hz0 = p.hz = (p.hz - zeroDiff) % (Math.PI * 2);
            });
        }
        //删除之前添加的点
        if (this.surveyResultList.length > 3) {
            this.surveyResultList.splice(this.surveyResultList.length - 1, 1);
        }
    }
    /**
    * 判断是否需要计算归零差,判断标准是测回第一点和最后一点是否为同一点
    * 当测回点数超过4个的时候就需要增加定向点归零的判断
    */
    _isZeroHzNeeded() {
        if (this.surveyResultList.length < 4)
            return false;
        var firstPt = this.surveyResultList[0];
        var lastPt = this.surveyResultList[this.surveyResultList.length - 1];
        return (firstPt.name === lastPt.name) && firstPt.pass && lastPt.pass;
    }
    /**
     * 从TPS中深拷贝要测的测点,作为本次测回数据的起始测量数据
     */
    copyPointsFromTPS(tps) {
        this.surveyResultList = [];
        tps.studyPointList.forEach(p => {
            if (typeof (p.selected) === 'undefined') p.selected = true;
            if (p.selected) {
                var pt = Object.assign(new SurveyPoint(), p);
                this.surveyResultList.push(pt);
            }
        });
    }
    /**
     * 查找测量点
     */
    findPoint(key) {
        return this.surveyResultList[key];
    }
}
exports.SurveyTurn = SurveyTurn;
var Face;
(function (Face) {
    /** 盘左,正镜 */
    Face[Face["Face1"] = 0] = "Face1";
    /** 盘右,倒镜 */
    Face[Face["Face2"] = 1] = "Face2";
})(Face || (Face = {}));
exports.Face = Face;
var ObserveMethod;
(function (ObserveMethod) {
    /** 全圆测回 */
    ObserveMethod[ObserveMethod["FullCircle"] = 0] = "FullCircle";
    /** 半测回 */
    ObserveMethod[ObserveMethod["HalfCircle"] = 1] = "HalfCircle";
})(ObserveMethod || (ObserveMethod = {}));
exports.ObserveMethod = ObserveMethod;
